//
// Created by LiuYou on 2021/10/12.
//

#ifndef LINUXMULTITHREADSERVERPROGRAMMING_MUTEXLOCK_HPP
#define LINUXMULTITHREADSERVERPROGRAMMING_MUTEXLOCK_HPP


#include <pthread.h>


/*
 * MutexLock, MutexLockGuard 这是两个工具类。
 */

/**
 * @brief MutexLock 封装临界区(封装了互斥量)。
 * @details 使用 RAII手法 封装pthread互斥量(mutex)的创建和销毁, mutex是不可重入的。
 * MutexLock一般是别的class的成员变量, 用来保护其内部字段。
 */
class MutexLock {
public:
    /*
     * lock()成员方法和unlock()成员方法仅供 MutexLockGuard 调用, 严禁用户代码调用！
     */

    void lock() {
        pthread_mutex_lock( &pthreadMutex );
    }

    void unlock() {
        pthread_mutex_unlock( &pthreadMutex );
    }

public:
    MutexLock() {
        pthread_mutex_init( &pthreadMutex, nullptr );
    }

    ~MutexLock() {
        pthread_mutex_destroy( &pthreadMutex );
    }

    /*
     * MutexLock class 不允许拷贝构造和拷贝赋值, 以及移动构造和移动赋值！
     */

    MutexLock(const MutexLock& rhs) = delete;

    MutexLock& operator==(const MutexLock& rhs) = delete;

    MutexLock(MutexLock&& rhs) = delete;

    MutexLock& operator==(MutexLock&& rhs) = delete;

private:
    pthread_mutex_t pthreadMutex{};
};


/**
 * @brief MutexLockGuard 封装临界区的进入和退出, 即加锁和解锁(即封装了互斥量的加锁与解锁)。
 * @details MutexLockGuard一般是一个栈上的对象, 这个对象的作用域刚好等于临界区域的代码(
 * 即作用域刚好是临界区域结束时, 它就自动析构销毁了)。
 */
class MutexLockGuard {
public:
    explicit MutexLockGuard(MutexLock& mutexLock) : mutexLock( mutexLock ) {
        this->mutexLock.lock();
    }

    ~MutexLockGuard() {
        mutexLock.unlock();
    }

    MutexLockGuard(const MutexLockGuard& rhs) = delete;

    MutexLockGuard& operator==(const MutexLockGuard& rhs) = delete;

    MutexLockGuard(MutexLockGuard&& rhs) = delete;

    MutexLockGuard& operator==(MutexLockGuard&& rhs) = delete;

private:
    MutexLock& mutexLock;
};


#define MutexLockGuard(x) static_assert(false, "“缺少互斥锁保护(MutexLockGuard)变量名称”")


#endif //LINUXMULTITHREADSERVERPROGRAMMING_MUTEXLOCK_HPP
